package com.zengdada.dml.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zengdada.authority.exception.RoutineException;
import com.zengdada.authority.model.DmlColumn;
import com.zengdada.authority.utils.CommonUtils;
import com.zengdada.authority.utils.where.Where;
import com.zengdada.authority.utils.mapper.Page;
import com.zengdada.authority.utils.mapper.Sort;
import com.zengdada.authority.utils.where.result.AnalysisResultMerge;
import com.zengdada.dml.model.DmlColumnExtend;
import com.zengdada.dml.model.DmlExtend;
import com.zengdada.dml.model.type.*;
import com.zengdada.dml.utils.DmlExecuteReturn;
import com.zengdada.dml.utils.DmlWhere;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.commons.beanutils.converters.DateTimeConverter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.script.*;
import javax.servlet.http.HttpServletRequest;
import javax.swing.table.DefaultTableModel;
import java.sql.*;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Component
@Scope("prototype")
public class DmlExecutor {

    private ScriptEngine nashorn;

    private HttpServletRequest request;
    private Connection conn;

    @Value("${plat.function.obtain.login.user.id:'没有配置获取登录用户ID的方法！'}")
    private String obtainLoginUserIdFunction;

    @Value("${plat.function.obtain.login.user.name:'没有配置获取登录用户NAME的方法！'}")
    private String obtainLoginUserNameFunction;

    @Value("${authority.application.id}")
    private String applicationId;

    static {
        DateTimeConverter dtConverter = new DateConverter();
        dtConverter.setPatterns(new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"});
        ConvertUtils.register(dtConverter, Date.class);
    }


    public DmlExecutor() {
    }

    public DmlExecutor(HttpServletRequest request, Connection conn) {
        init(request, conn);
    }

    public DmlExecutor(HttpServletRequest request, Connection conn, ScriptEngine engine) {
        this.request = request;
        this.conn = conn;
        this.nashorn = engine;
    }

    public DmlExecutor init(HttpServletRequest request, Connection conn) {
        this.request = request;
        this.conn = conn;
        this.nashorn = new ScriptEngineManager().getEngineByName("Nashorn");
        if (request != null) {
            Bindings bindings = nashorn.createBindings();
            bindings.put("session", this.request.getSession());
            bindings.put("application", this.request.getServletContext());
            bindings.put("request", this.request);
            this.nashorn.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
            try {
                this.nashorn.eval("var uuid = function(){ return java.util.UUID.randomUUID().toString(); }");
                this.nashorn.eval("var getUserId = function(){ return " + obtainLoginUserIdFunction + "; }");
                this.nashorn.eval("var getUserName = function(){ return " + obtainLoginUserNameFunction + "; }");
                this.nashorn.eval("var getApplicationId = function(){ return '" + applicationId + "'; }");
            } catch (ScriptException e) {
                e.printStackTrace();
            }
        }
        return new DmlExecutor(request, conn, this.nashorn);
    }

    /**
     * 执行dml 语句
     *
     * @param dml
     * @return
     * @throws Exception
     */
    public DmlExecuteReturn execute(DmlExtend dml) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug(String.format("==>     dmlType：%s", dml.getClass().getSimpleName()));
            log.debug(String.format("==>         sql：%s", dml.getRawDml()));
        }
        DmlExecuteReturn ret = new DmlExecuteReturn();
        ret.setDmlType(dml.getDmlType());
//        List<Integer> outParamIndices = new ArrayList<>();
        int paramCount = 0;
        List<DmlColumnExtend> cols = null;
        if (dml instanceof Insert || dml instanceof Update || dml instanceof Delete) {
            try (PreparedStatement ps = conn.prepareStatement(dml.getRawDml())) {
                cols = dml.getColumns(DmlColumnExtend.IN_PARAM_COLUMN, DmlColumnExtend.INOUT_PARAM_COLUMN);
                List<Object> colValues = getColsValue(cols);
                StringBuilder logStr = new StringBuilder("==> paramValues：");
                for (Object value : colValues) {
                    ps.setObject(++paramCount, value instanceof Date ? new java.sql.Date(((Date) value).getTime()) : value);
                    if (log.isDebugEnabled()) {
                        logStr.append(value == null ? "null" : value.toString()).append("(").append(value != null ? value.getClass().getSimpleName() : "").append(") ,");
                    }
                }
                if (logStr.charAt(logStr.length() - 1) == ',') {
                    logStr.deleteCharAt(logStr.length() - 1);
                }
                if (log.isDebugEnabled()) {
                    log.debug("==>  paramNames：{}", String.join(" , ", dml.getColumns().stream().map(DmlColumn::getName).collect(Collectors.joining(" , "))));
                    log.debug(logStr.toString());
                }
                ret.setRowsUpdated(ps.executeUpdate());
                cols.forEach(col -> ret.getData().addColumn(col.getColumnType()));
                ret.getData().addRow(colValues.toArray());
                if (log.isDebugEnabled()) {
                    log.debug("<==       total：{}", ret.getRowsUpdated());
                }
            }
        } else if (dml instanceof PlSql || dml instanceof Procedure || dml instanceof Function) {
            try (CallableStatement cs = conn.prepareCall(dml.getRawDml())) {
                cols = dml.getColumns(DmlColumnExtend.IN_PARAM_COLUMN, DmlColumnExtend.INOUT_PARAM_COLUMN,
                        DmlColumnExtend.OUT_PARAM_COLUMN);
                StringBuilder logStr = new StringBuilder("==>      params：");
                for (DmlColumnExtend col : cols) {
                    switch (col.getColumnType()) {
                        case DmlColumnExtend.IN_PARAM_COLUMN:
                        case DmlColumnExtend.INOUT_PARAM_COLUMN:
                            Object value = getColValue(col);
                            cs.setObject(++paramCount, value instanceof Date ? new java.sql.Date(((Date) value).getTime()) : value);
                            if (log.isDebugEnabled()) {
                                logStr.append("(").append(col.getColumnType() == 1 ? "in" : "inOut").append(") ")
                                        .append(col.getLabel()).append(" --> ")
                                        .append(value == null ? "null" : value.toString()).append("(").append(value == null ? "" : value.getClass().getSimpleName()).append(") ,");
                            }
                            break;
                        case DmlColumnExtend.OUT_PARAM_COLUMN:
                        case DmlColumnExtend.RET_VALUE_COLUMN:
                            cs.registerOutParameter(++paramCount, col.getSqlType());
//                            outParamIndices.add(paramCount);
                            ret.getData().addColumn(col.getName());
                            if (log.isDebugEnabled()) {
                                logStr.append("(").append(col.getColumnType() == 2 ? "out" : "ret").append(") ")
                                        .append(col.getLabel()).append(" --> ")
                                        .append("输出").append("(").append(col.getDataTypeClass().getSimpleName()).append(") ,");
                            }
                            break;
                        default:
                            break;
                    }
                }
                if (logStr.charAt(logStr.length() - 1) == ',') {
                    logStr.deleteCharAt(logStr.length() - 1);
                }
                if (log.isDebugEnabled()) {
                    log.debug(logStr.toString());
                }
                cs.execute();
                ret.getData().addRow(getOutputParamValues(cs, cols));
                if (log.isDebugEnabled()) {
                    log.debug("<==       total：{}", ret.getData().getRowCount());
                }
            }
        } else {
            throw new IllegalArgumentException(String.format("语句类型不受支持:%s", dml.getClass().getName()));
        }
        return ret;
    }

    private static final Pattern ANYWHERE_PATTERN = Pattern.compile("\\sanyWhere");


    /**
     * 执行dml查询
     *
     * @param select dml
     * @param page   分页信息 为空时将自动检查 page，pageSize 参数，如果还为空 将不进行分页查询
     * @param where  查询条件 为空时将自动检查 searchs 参数（满足Where类型的JSON字符串），如果还为空 将不进行条件搜索
     * @param sorts  排序信息 为空时将自动检查 sorts 参数（满足Sort类型的JSON数组字符串），如果还为空 将不进行排序
     * @return
     * @throws Exception
     */
    public DmlExecuteReturn executeQuery(StaticSelect select, Page page, Where where, List<Sort> sorts) throws Exception {

        // 分页信息
        if (page == null) {
            String pageNum = request.getParameter("page");
            String pageSize = request.getParameter("pageSize");
            if (!StringUtils.isAllBlank(pageNum, pageSize)) {
                page = new Page();
                if (StringUtils.isNotBlank(pageNum)) {
                    page.setPage(parseInt(pageNum, 1));
                }
                if (StringUtils.isNotBlank(pageSize)) {
                    page.setPageSize(parseInt(pageSize, 10) > select.getMaxPageSize() && select.getMaxPageSize() > 0 ? select.getMaxPageSize() : parseInt(pageSize, 10));
                }
            }
        }
        String jsonSearchs = request.getParameter("searchs");
        String jsonSorts = request.getParameter("sorts");
//        String jsonSearchs = "";
//        String jsonSorts = "";
        if (log.isDebugEnabled()) {
            log.debug("filters: {}", jsonSearchs);
            log.debug("sorters: {}", jsonSorts);
        }

        // 筛选条件
        where = where == null ? Where.formJsonString(jsonSearchs) : where;
        // 排序条件
        List<Sort> sorters = (sorts == null || sorts.size() == 0) ? JSON.parseArray(jsonSorts, Sort.class) : sorts;

        AnalysisResultMerge analysis = new AnalysisResultMerge();
        List<Object> paramValues = getColsValue(select.getColumns(DmlColumnExtend.IN_PARAM_COLUMN, DmlColumnExtend.INOUT_PARAM_COLUMN));
        // 用于数据条数统计语句的参数
        List<Object> countParamValues = new ArrayList<>(paramValues);
        String sql = select.getRawDml();
        String countSql = "";

        // 得到所有显示的列
        StringBuilder selectAlias = new StringBuilder();
        if (select.getType() != StaticSelect.SelectType.select.getType()) {
            List<DmlColumnExtend> selectColumn = select.getColumnsForAttr(512);
            if (selectColumn.size() == 0) {
                throw new RuntimeException("没有可显示的字段，请配置dmlColumn attrs 属性包含512");
            }
            for (DmlColumn dmlColumn : selectColumn) {
                selectAlias.append(StringUtils.isBlank(dmlColumn.getDisplayExpr()) ? dmlColumn.getName() : dmlColumn.getDisplayExpr());
                // 如果是导出
                if (StaticSelect.SelectType.export.getType() == select.getType() || StaticSelect.SelectType.selectChinese.getType() == select.getType()) {
                    selectAlias.append(" \"").append(dmlColumn.getCaption()).append("\"");
                } else {
                    selectAlias.append(" ").append(" \"").append(dmlColumn.getLabel()).append("\"");
                }
                selectAlias.append(", ");
            }
            if (selectAlias.length() > 2 && selectAlias.charAt(selectAlias.length() - 2) == ',') {
                selectAlias.deleteCharAt(selectAlias.length() - 2);
            }
        }
        // 排序处理
        if (sorters != null && sorters.size() > 0) {
            List<String> extraSorters = new ArrayList<>();
            for (Sort sort : sorters) {
                if (!sort.isNotNull()) {
                    continue;
                }
                DmlColumnExtend col = select.findColByLabel(sort.getField());
                if (col == null) {
                    continue;
                }
                if (!col.hasAttr(DmlColumnExtend.ATTR_SORTABLE)) {
                    continue;
                }
                extraSorters.add(sort.getOrderDetailed());
            }
            if (extraSorters.size() > 0) {
                sql = String.format("SELECT ORDER_TEMP.* FROM (%s) ORDER_TEMP ORDER BY ORDER_TEMP.%s", sql, String.join(", ORDER_TEMP.", extraSorters.toArray(new String[0])));
            }
        }
        if (page != null) {
            select.setPageSize(page.getPageSize());
        }
        sql = String.format("SELECT %s, rownum as PAGING_ROW_NUM FROM (%s) PLAT_TEMP", selectAlias.length() > 0 ? selectAlias.toString() : "PLAT_TEMP.*", sql);
        if (select.needWrap() && where != null) {
            // 筛选条件处理
            analysis = JSONObject.parseObject(JSONObject.toJSONString(where), DmlWhere.class).analysisMerge(select);
        }
        // 求总
        if (page != null && select.getType() != StaticSelect.SelectType.export.getType()) {
            countSql = String.format("SELECT COUNT(0) TOTAL FROM (%s) COUNT_TMP", select.getRawDml());

            if (select.getDmlType() == DmlExtend.DML_TYPE_ANY_WHERE) {
                countSql = anyWhereBuildSqlAndHandleParam(countParamValues, countSql, analysis.getAnyWhereExtraFilter(), analysis.getAnyWhereParamValues());
            }
            if (!analysis.isNull() && StringUtils.isNotBlank(analysis.getExtraFilter())) {
                countSql = String.format("%s WHERE %s", countSql, analysis.getExtraFilter());
            }
            countParamValues.addAll(analysis.getParamValues());
        }
//        if (select.getDmlType() == DmlExtend.DML_TYPE_ANY_WHERE && extraFilters.size() == 0) {
////            if (extraFilters.size() == 0) throw new RuntimeException("'anyWhere'查询， 必须设置查询条件！！");
//            extraFilters.add("1 = 1");
//        }

        // 拼接条件语句
        if (!analysis.isNull() && select.getDmlType() == DmlExtend.DML_TYPE_ANY_WHERE) {
            sql = anyWhereBuildSqlAndHandleParam(paramValues, sql, analysis.getAnyWhereExtraFilter(), analysis.getAnyWhereParamValues());
        }

        // 添加分页条件
        if (page != null && select.getPageSize() > 0) {
            analysis.setExtraFilter(StringUtils.isNotBlank(analysis.getExtraFilter()) ? analysis.getExtraFilter() + " AND rownum < ? " : " rownum < ? ");
//            outExtraFilters.add("rownum < ?");
            analysis.addParamValue(page.getPage() * page.getPageSize() + 1);
        }

        if (StringUtils.isNotBlank(analysis.getExtraFilter())) {
            sql = String.format("%s WHERE %s", sql, analysis.getExtraFilter());
        }

        // 拼接分页结束条件语句
        if (page != null && select.getPageSize() > 0) {
            sql = String.format("SELECT * FROM (%s) WHERE PAGING_ROW_NUM > ? ", sql);
            analysis.addParamValue((page.getPage() - 1) * page.getPageSize());
        }
        paramValues.addAll(analysis.getParamValues());

        DmlExecuteReturn result = execute(sql, paramValues);
        result.setDmlType(select.getDmlType());
        if (!"".equals(countSql)) {
            DmlExecuteReturn countReturn = execute(countSql, countParamValues);
            result.setTotalRow(parseInt(String.valueOf(countReturn.getDataMap().get(0).get("TOTAL")), result.getDataMap().size()));
        }
        return result;
    }

    private String anyWhereBuildSqlAndHandleParam(List<Object> paramValues, String sql, String anyWhereExtraFilter, List<Object> anyWhereParamValues) {
        StringBuffer buf = new StringBuffer();
        Matcher matcher = ANYWHERE_PATTERN.matcher(sql);
        while (matcher.find()) {
            matcher.appendReplacement(buf, StringUtils.isBlank(anyWhereExtraFilter) ? " " : (" AND " + anyWhereExtraFilter));
            paramValues.addAll(CommonUtils.zInStrAppearCount(buf.toString(), "\\?") - anyWhereParamValues.size(), anyWhereParamValues);
        }
        matcher.appendTail(buf);
        return buf.toString();
    }

    private DmlExecuteReturn execute(String sql, List<Object> paramValues) throws SQLException {
        DmlExecuteReturn ret = new DmlExecuteReturn();
        int paramCount = 0;
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            if (log.isDebugEnabled()) {
                log.debug("==>     dmlType：StaticSelect");
                log.debug(String.format("==>         sql：%s", sql));
            }
            StringBuilder logStr = new StringBuilder("==> paramValues：");
            for (Object value : paramValues) {
                ps.setObject(++paramCount, value instanceof Date ? new java.sql.Date(((Date) value).getTime()) : value);
                if (log.isDebugEnabled()) {
                    logStr.append(value == null ? "null" : value.toString()).append("(").append(value == null ? "" : value.getClass().getSimpleName()).append(") ,");
                }
            }
            if (logStr.charAt(logStr.length() - 1) == ',') {
                logStr.deleteCharAt(logStr.length() - 1);
            }
            if (log.isDebugEnabled()) {
                log.debug(logStr.toString());
            }
            try (ResultSet rs = ps.executeQuery()) {
                ResultSetMetaData rm = rs.getMetaData();
                int colCount = rm.getColumnCount();
//                List<String> colNames = new ArrayList<String>();
                DefaultTableModel data = ret.getData();
                for (int i = 0; i < colCount; i++) {
                    String colName = rm.getColumnLabel(i + 1);
                    if (StringUtils.isBlank(colName)) {
                        colName = rm.getColumnName(i + 1);
                    }
                    if ("paging_row_num".equals(colName.toLowerCase())) {
                        continue;
                    }
                    data.addColumn(colName);
                }
                colCount = data.getColumnCount();
                while (rs.next()) {
                    Object[] row = new Object[colCount];
                    for (int i = 0; i < colCount; i++) {
                        row[i] = rs.getObject(data.getColumnName(i));
                    }
                    data.addRow(row);
                }
                if (log.isDebugEnabled()) {
                    log.debug("<==       total：{}", data.getRowCount());
                }
            }
        }
        return ret;
    }


    public int getCount(StaticSelect select, Where where) throws ScriptException, SQLException {
        String searchs = request.getParameter("searchs");
        if (log.isDebugEnabled()) {
            log.debug("filters: " + searchs);
        }

        // 筛选条件
        where = (where == null) ? JSON.parseObject(searchs, Where.class) : where;

        List<Object> paramValues = getColsValue(select.getColumns(DmlColumnExtend.IN_PARAM_COLUMN, DmlColumnExtend.INOUT_PARAM_COLUMN));

        AnalysisResultMerge analysis = new AnalysisResultMerge();
        String countSql = String.format("SELECT COUNT(0) TOTAL FROM (%s) COUNT_TMP", select.getRawDml());
        if (select.needWrap()) {
            // 筛选条件处理
//            handleSearch(select, filters, anyWhereParamValues, outParamValues, anyWhereExtraFilters, outExtraFilters);
            analysis = JSONObject.parseObject(JSONObject.toJSONString(where), DmlWhere.class).analysisMerge(select);
        }
        if (select.getDmlType() != DmlExtend.DML_TYPE_ANY_WHERE) {
            countSql = anyWhereBuildSqlAndHandleParam(paramValues, countSql, analysis.getAnyWhereExtraFilter(), analysis.getAnyWhereParamValues());
        }
        if (!analysis.isNull() && StringUtils.isNotBlank(analysis.getExtraFilter())) {
            countSql = String.format("%s WHERE %s", countSql, analysis.getExtraFilter());
        }
        paramValues.addAll(analysis.getParamValues());
        DmlExecuteReturn countReturn = execute(countSql, paramValues);
        countReturn.setDmlType(select.getDmlType());
        return parseInt(String.valueOf(countReturn.getDataMap().get(0).get("total")), 0);
    }


//    private void handleSearch(StaticSelect select, List<PublicSearch> filters, List<Object> anyWhereParamValues, List<Object> outParamValues, List<String> anyWhereExtraFilters, List<String> outExtraFilters) {
//        for (PublicSearch search : filters) {
//            // 值和操作符同时为空则忽略该条件
//            if (!search.isValid()) continue;
//            // 通过列名称找到该列
//            DmlColumnExtend column = select.findColByLabel(search.getField());
//            // 在预定列中没有查找到筛选列
//            if (column == null) continue;
//            // 列不具有可查询属性
//            if (!column.hasAttr(DmlColumnExtend.ATTR_QUERYABLE)) continue;
//            boolean anyWhere = column.getColumnType() == DmlColumnExtend.ANY_WHERE_COLUMN;
//            //
//            Object val = search.getConditionVal();
//            List<String> extraFilterContents = new ArrayList<>();
//            if (val != null) {
//                if (val instanceof List) {
//                    ((List) val).forEach(i -> {
//                        if (anyWhere) anyWhereParamValues.add(i);
//                        else outParamValues.add(i);
//                        extraFilterContents.add("?");
//                    });
//                } else if (val instanceof PublicSearchRangeAssist) {
//                    if (anyWhere) {
//                        anyWhereParamValues.add(((PublicSearchRangeAssist) val).getFront());
//                        anyWhereParamValues.add(((PublicSearchRangeAssist) val).getAfter());
//                        anyWhereExtraFilters.add(String.format("%s ? AND ? %s", search.getConditionAndPrefix(column.getName()), search.getConditionSuffix()));
//                    } else {
//                        outParamValues.add(((PublicSearchRangeAssist) val).getFront());
//                        outParamValues.add(((PublicSearchRangeAssist) val).getAfter());
//                        outExtraFilters.add(String.format("%s ? AND ? %s", search.getConditionAndPrefix(column.getName()), search.getConditionSuffix()));
//                    }
//                    continue;
//                } else {
//                    if (anyWhere) anyWhereParamValues.add(val);
//                    else outParamValues.add(val);
//                    extraFilterContents.add("?");
//                }
//            }
//            String sql = String.format("%s %s %s", search.getConditionAndPrefix(column.getName()), String.join(", ", extraFilterContents), search.getConditionSuffix());
//            if (anyWhere) anyWhereExtraFilters.add(sql);
//            else outExtraFilters.add(sql);
//        }
//    }


    private static int parseInt(String sval, int fallback) {
        if (sval == null || sval.isEmpty()) {
            return fallback;
        }
        try {
            return Integer.parseInt(sval);
        } catch (NumberFormatException ex) {
            return fallback;
        }
    }

    /**
     * 取表达式的值
     *
     * @param expr
     * @return
     * @throws ScriptException
     */
    private Object evalExpression(String expr) throws ScriptException {
        if (log.isDebugEnabled()) {
            log.debug(String.format(" 表达式：%s", expr));
        }
        if (nashorn == null) {
            throw new NullPointerException("nashorn为null,request对象未传递");
        }
        Object val = nashorn.eval(expr);
        if (log.isDebugEnabled()) {
            log.debug(String.format(" 表达式值：%s", val));
        }
        return val;
    }

    /**
     * 单列取值
     *
     * @param col
     * @return
     * @throws ScriptException
     */
    private Object getColValue(DmlColumnExtend col)
            throws ScriptException {

        Object value = col.getValue();

        // 获取程序赋予dmlcolumn上面的值
        if (value != null) {
            return value;
        }

        if (this.request == null) {
            throw new RoutineException("request 未传值或者为null,不能获取参数值");
        }
        value = col.getExpression() != null ? evalExpression(col.getExpression()) : this.request.getParameter(col.getLabel());
//            log.debug(String.format("%s,%s", col.getLabel().toLowerCase(), this.request.getParameter(col.getLabel().toLowerCase())));
        value = (value == null) ? col.getDefaultValue() : value;

        if (col.hasAttr(DmlColumnExtend.ATTR_REQUIRED)) {
            if (value == null || (value instanceof String && ((String) value).isEmpty())) {
                throw new IllegalArgumentException(String.format("缺少参数[%s]", col.getCaption()));
            }
        }

        if (!String.class.equals(col.getDataTypeClass()) && value != null) {
            if (Date.class.equals(col.getDataTypeClass())) {
                if (value instanceof String) {
                    try {
                        value = CommonUtils.randomLengthStringToDate(String.valueOf(value));
                    } catch (ParseException e) {
                        throw new IllegalArgumentException("非法时间类型数据异常" + e.getMessage());
                    }
                } else if (!(value instanceof Date)) {
                    throw new IllegalArgumentException("非法时间类型数据异常");
                }
            } else {
                value = ConvertUtils.convert(value, col.getDataTypeClass());
            }
        }
        return value;
    }

    /**
     * 取字段值
     *
     * @param cols
     * @return
     * @throws ScriptException
     */
    private List<Object> getColsValue(List<DmlColumnExtend> cols) throws ScriptException {
        List<Object> values = new ArrayList<>();
        for (DmlColumnExtend col : cols) {
            values.add(getColValue(col));
        }
        return values;
    }

    /**
     * 取OUTPUT参数值
     *
     * @param cs
     * @param cols
     * @return
     * @throws SQLException
     */
    private static Object[] getOutputParamValues(CallableStatement cs, List<DmlColumnExtend> cols) throws SQLException {
        int colIndex = 0;
        List<Object> output = new ArrayList<Object>();
        for (DmlColumnExtend col : cols) {
            ++colIndex;
            if (col.getColumnType() == DmlColumnExtend.INOUT_PARAM_COLUMN || col.getColumnType() == DmlColumnExtend.OUT_PARAM_COLUMN) {
                output.add(cs.getObject(colIndex));
            }
        }
        return output.toArray();
    }

    public static void main(String[] args) {
        DmlExecutor executor = new DmlExecutor();
//        ServletA
//        executor.init(new HttpServletRequest(),null);
        DmlWhere dmlWhere = new DmlWhere();
        dmlWhere.setFormulaE(Where.Formula.AND);
        dmlWhere.setParams(new ArrayList<Where>() {{
            add(new Where("name", "aaa"));
            add(new Where("name1", "aaa1"));
            add(new Where("age", "10"));
            add(new Where(Where.Formula.OR, new ArrayList<Where>() {{
                add(new Where("age", Where.Formula.RANGE, "9~~10"));
                add(new Where("name", "aaa"));
            }}));
        }});
        StaticSelect select = new StaticSelect();
        select.setRawDml("select * from test where 1 = 1 anyWhere");
        select.add("name", "", String.class);
        select.add("name1", "", String.class);
        select.add("age", "", String.class);
        select.setDmlType(-1);
        List<DmlColumnExtend> columns = select.getColumns();
        for (DmlColumnExtend column : columns) {
            column.setValue("000");
            column.setColumnType(0);
            column.setAttr(32, true);
        }
        columns.get(1).setColumnType(-1);
        try {
            executor.executeQuery(select, new Page(), dmlWhere, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}